package com.kly.manager.auth;

import cn.dev33.satoken.stp.StpInterface;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.json.JSONUtil;
import com.kly.constants.UserConstant;
import com.kly.domain.dto.user.UserDto;
import com.kly.domain.entity.Picture;
import com.kly.domain.entity.Space;
import com.kly.domain.entity.SpaceUser;
import com.kly.domain.entity.User;
import com.kly.domain.enums.SpaceRoleEnum;
import com.kly.domain.enums.SpaceTypeEnum;
import com.kly.exception.ErrorCode;
import com.kly.exception.ThrowUtils;
import com.kly.manager.auth.model.SpaceUserAuthContext;
import com.kly.service.PictureService;
import com.kly.service.SpaceService;
import com.kly.service.SpaceUserService;
import com.kly.service.UserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

import static com.kly.constants.UserConstant.USER_LOGIN_STATE;

/**
 * 自定义权限加载接口实现类
 */
@Component    // 保证此类被 SpringBoot 扫描，完成 Sa-Token 的自定义权限验证扩展
public class StpInterfaceImpl implements StpInterface {


    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Resource
    private SpaceService spaceService;

    @Resource
    private PictureService pictureService;

    @Resource
    private SpaceUserService spaceUserService;

    @Resource
    private UserService userService;

    /**
     * 返回一个账号所拥有的权限码集合
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        // 本 list 仅做模拟，实际项目中要根据具体业务逻辑来查询权限
        if (!("space").equals(loginType)) {
            return Collections.emptyList();
        }
        // 管理员权限处理
        List<String> ADMIN_PERMISSION = SpaceUserAuthManage.getPermissionByRole(SpaceRoleEnum.ADMIN.getValue());
        // 获取上下文对象
        SpaceUserAuthContext authContext = getAuthContext();
        if (isAllFieldsNull(authContext)) {
            return ADMIN_PERMISSION;
        }
        // 获取用户登录信息
        UserDto userInfo = (UserDto) StpKit.SPACE.getSessionByLoginId(loginId).get(USER_LOGIN_STATE);
        ThrowUtils.throwIf(ObjUtil.isNull(userInfo), ErrorCode.NOT_LOGIN_ERROR, "未登录");
        Long userId = userInfo.getId();
        // 优先获取spaceUser对象
        SpaceUser spaceUser = authContext.getSpaceUser();
        if (ObjUtil.isNotNull(spaceUser)) {
            //     直接获取角色获取权限
            return SpaceUserAuthManage.getPermissionByRole(spaceUser.getSpaceRole());
        }
        // 获取spaceUserId 信息
        Long spaceUserId = authContext.getSpaceUserId();
        if (ObjUtil.isNotNull(spaceUserId)) {
            spaceUser = spaceUserService.getById(spaceUserId);
            ThrowUtils.throwIf(ObjUtil.isNull(spaceUser), ErrorCode.NOT_FOUND_ERROR);

            SpaceUser loginSpaceUser = spaceUserService.lambdaQuery()
                    .eq(SpaceUser::getSpaceId, spaceUser.getSpaceId())
                    .eq(SpaceUser::getUserId, userId)
                    .one();
            if (ObjUtil.isNull(loginSpaceUser)) {
                return Collections.emptyList();
            }
            return SpaceUserAuthManage.getPermissionByRole(loginSpaceUser.getSpaceRole());
        }
        // 通过spaceId 或 pictureId 获取
        Long spaceId = authContext.getSpaceId();
        if (ObjUtil.isNull(spaceId)) {
            Long pictureId = authContext.getPictureId();
            // 默认返回管理员权限
            if (ObjUtil.isNull(pictureId)) {
                return ADMIN_PERMISSION;
            }
            //     查询图片信息
            Picture picture = pictureService.lambdaQuery()
                    .eq(Picture::getId, pictureId)
                    .one();
            ThrowUtils.throwIf(ObjUtil.isNull(picture), ErrorCode.NOT_FOUND_ERROR);

            if (picture.getUserId().equals(userId) || UserConstant.ADMIN_ROLE.equals(userInfo.getUserRole())) {
                // 个人创建图片或管理员具有全部权限
                return ADMIN_PERMISSION;
            } else {
                //     其他人只能查询
                return SpaceUserAuthManage.getPermissionByRole(SpaceRoleEnum.VIEWER.getValue());
            }
        }

        // 获取space信息
        // 判断空间类型
        Space space = spaceService.getById(spaceId);
        ThrowUtils.throwIf(ObjUtil.isNull(space), ErrorCode.NOT_FOUND_ERROR);
        if (SpaceTypeEnum.PRIVATE.getType().equals(space.getSpaceType())) {
            if (space.getUserId().equals(userId) || UserConstant.ADMIN_ROLE.equals(userInfo.getUserRole())) {
                // 个人创建空间或管理员具有全部权限
                return ADMIN_PERMISSION;
            } else {
                //     其他人没有权限
                return Collections.emptyList();
            }
        }
        // 团队空间
        spaceUser = spaceUserService.lambdaQuery()
                .eq(SpaceUser::getSpaceId, spaceId)
                .eq(SpaceUser::getUserId, userId)
                .one();
        if (ObjUtil.isNull(spaceUser)) {
            return Collections.emptyList();
        }
        return SpaceUserAuthManage.getPermissionByRole(spaceUser.getSpaceRole());
    }

    /**
     * 判断authContext字段是否全为空 反射判断字段
     */
    private boolean isAllFieldsNull(Object obj) {
        if (obj == null) {
            return true;
        }

        return Arrays.stream(ReflectUtil.getFields(obj.getClass()))
                .map(filed -> ReflectUtil.getFieldValue(obj, filed))
                .allMatch(Objects::isNull);
    }

    /**
     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        // 本 list 仅做模拟，实际项目中要根据具体业务逻辑来查询角色
        long userId = StpKit.SPACE.getLoginIdAsLong();
        User userDb = userService.getById(userId);
        if (ObjUtil.isNull(userDb)) {
            return Collections.emptyList();
        }
        return Collections.singletonList(userDb.getUserRole());
    }


    /**
     * 获取context对象
     */
    private SpaceUserAuthContext getAuthContext() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String header = request.getHeader(Header.CONTENT_TYPE.getValue());
        SpaceUserAuthContext authRequest = null;
        // get post请求
        if (ContentType.JSON.getValue().equals(header)) {
            String body = ServletUtil.getBody(request);
            authRequest = JSONUtil.toBean(body, SpaceUserAuthContext.class);
        } else {
            Map<String, String> paramMap = ServletUtil.getParamMap(request);
            authRequest = JSONUtil.toBean(JSONUtil.toJsonStr(paramMap), SpaceUserAuthContext.class);
        }

        Long id = authRequest.getId();
        if (ObjUtil.isNotNull(id)) {
            //     判断请求前缀
            String uri = request.getRequestURI();
            String pathUri = uri.replace(contextPath + "/", "");
            String path = StrUtil.subBefore(pathUri, "/", false);
            switch (path) {
                case "space":
                    authRequest.setSpaceId(id);
                    break;
                case "picture":
                    authRequest.setPictureId(id);
                    break;
                case "spaceUser":
                    authRequest.setSpaceUserId(id);
                    break;
                default:
            }

        }
        return authRequest;
    }
}
